package mop.gui;

import java.util.LinkedList;
import java.util.List;

import javax.swing.JOptionPane;

import mop.controller.ChangeClockController;
import mop.controller.ControllerVisitor;
import mop.controller.CreateProjectController;
import mop.controller.CreateResourceController;
import mop.controller.CreateTaskController;
import mop.controller.CreateUserController;
import mop.controller.FocusWorkController;
import mop.controller.LoginController;
import mop.controller.MakeResourceReservationController;
import mop.controller.ModifyTaskDetailsController;
import mop.controller.RemoveProjectController;
import mop.controller.RemoveTaskController;
import mop.controller.UpdateTaskStatusController;
import mop.controller.UseCaseController;
import mop.gui.main.MainWindow;
import mop.model.task.TaskInterface;

/**
 * Main GUI class.
 *
 * @author  MOP Team 7
 */
public class GUI implements ControllerVisitor {

    /**
     * Constructor.
     *
     * @effect  Sets all given controllers.
     */
    public GUI(List<UseCaseController> controllers) {
        setControllers(controllers);
    }

    /***************************************************************************
     *                  	Main Window
     ***************************************************************************/

    /**
     * There can only be 1 main window!
     */
    private MainWindow mainWindow;

    /**
     * Returns the main window.
     *
     * @return	MainWindow
     */
    public MainWindow getMainWindow() {
        return this.mainWindow;
    }

    /**
     * Opens a MainWindow.
     */
    public void openMainWindow() {
        if (this.mainWindow == null) {
            try {
                this.mainWindow = new MainWindow(this);
            } catch (Exception ex) {
                handleError("Couldn't open Main Window!");
            }
        }

        this.mainWindow.setVisible(true);
    }

    /**
     * Clears all panels from the main window.
     */
    public void clearMainWindow() {
        if (this.mainWindow != null) {
            this.mainWindow.clearPanels();
        }
    }

    /**
     * Closes it.
     */
    public void closeMainWindow() {
        if (this.mainWindow != null) {
            this.mainWindow.dispose();
            this.mainWindow = null;
        }
    }

    /***************************************************************************
     *                          Handling messages
     ***************************************************************************/

    private boolean debug = false; // determines whether exception messages need to be parses in the console or not

    /**
     * Returns the debug option.
     *
     * @returns boolean debug
     */
    public boolean getDebug() {
        return this.debug;
    }

    /**
     * Sets the debug option.
     *
     * @param   boolean debug
     */
    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    /**
     * Adds property change listeners (the main window) to a list of tasks.
     *
     * @param   List<TaskInterface>
     */
    public void addListeners(List<TaskInterface> tasks) {
        if (mainWindow != null) {
            for (TaskInterface t : tasks) {
                t.removePropertyChangeListener(mainWindow);
                t.addPropertyChangeListener(mainWindow);
            }
        }
    }

    /**
     * Handles an exception by showing the error message.
     *
     * @param   exception
     *          Throwable
     */
    public void handleError(Throwable exception) {
        handleError(exception.toString());
        if (debug)
            exception.printStackTrace(System.err); // FOR DEBUGGING PURPOSES!
    }

    /**
     * Shows an error message.
     *
     * @param   exception
     *          Throwable
     */
    public void handleError(String e) {
        JOptionPane.showMessageDialog(null, e, "Error", JOptionPane.ERROR_MESSAGE);
        if (this.getMainWindow() != null) this.getMainWindow().update();
    }

    /**
     * Shows a "success" message.
     *
     * @param   s
     *          String
     */
    public void handleSuccess(String s) {
        JOptionPane.showMessageDialog(null, s, "Success", JOptionPane.INFORMATION_MESSAGE);
        if (this.getMainWindow() != null) this.getMainWindow().update();
    }

    /***************************************************************************
     *                          Controller references
     ***************************************************************************/

    private List<UseCaseController> controllers;

    /**
     * Sets the list of use case controllers & visits them.
     *
     * @param   List<UseCaseController>
     */
    public void setControllers(List<UseCaseController> controllers) {
        this.controllers = new LinkedList<UseCaseController>();
        this.controllers.addAll(controllers);

        // update main window
        try {
            openMainWindow();
            clearMainWindow();
            this.mainWindow.addController((LoginController) this.getController("Login"));
        } catch (Exception ex) {
            handleError("Login controller missing! :(");
            System.exit(1);
        }

        // accept controllers
        for (UseCaseController ucc : controllers) {
            ucc.accept(this);
        }
    }

    /**
     * Returns a controller object matching the given controller asset id.
     *
     * @param   String controller
     * @return  UseCaseController
     */
    public UseCaseController getController(String controller) throws Exception {
        for (UseCaseController ucc : controllers) {
            if (ucc.getAssetId() != null && ucc.getAssetId().toLowerCase().equals(controller.toLowerCase())) {
                return ucc;
            }
        }
        throw new Exception("Access denied!");
    }

    /***************************************************************************
     *                        Controllers | Logging in
     ***************************************************************************/

    @Override
    public void visit(LoginController c) {
        this.controllers.add(c);
    }

    /***************************************************************************
     *                        Controllers | Admin
     ***************************************************************************/

    @Override
    public void visit(CreateUserController c) {
        this.controllers.add(c);
        mainWindow.addAdminPanel();
        mainWindow.adminPanel.addController(c);
    }

    @Override
    public void visit(ChangeClockController c) {
        this.controllers.add(c);
        mainWindow.addAdminPanel();
        mainWindow.adminPanel.addController(c);
    }

    /***************************************************************************
     *                        Controllers | Projects
     ***************************************************************************/

    @Override
    public void visit(CreateProjectController c) {
        this.controllers.add(c);
        mainWindow.addProjectPanel();
        mainWindow.projectPanel.addController(c);
    }

    @Override
    public void visit(RemoveProjectController c) {
        this.controllers.add(c);
        mainWindow.addProjectPanel();
        mainWindow.projectPanel.addController(c);
    }

    /***************************************************************************
     *                        Controllers | Tasks
     ***************************************************************************/

    @Override
    public void visit(CreateTaskController c) {
        this.controllers.add(c);
        mainWindow.addTaskPanel();
        mainWindow.taskPanel.addController(c);
    }

    @Override
    public void visit(ModifyTaskDetailsController c) {
        this.controllers.add(c);
        mainWindow.addTaskPanel();
        mainWindow.taskPanel.addController(c);

        mainWindow.addFocusWorkPanel();
        mainWindow.focusWorkPanel.addController(c);
        mainWindow.focusWorkPanel.update();
    }

    @Override
    public void visit(RemoveTaskController c) {
        this.controllers.add(c);
        mainWindow.addTaskPanel();
        mainWindow.taskPanel.addController(c);
    }

    @Override
    public void visit(UpdateTaskStatusController c) {
        this.controllers.add(c);
        mainWindow.addTaskPanel();
        mainWindow.taskPanel.addController(c);

        mainWindow.addFocusWorkPanel();
        mainWindow.focusWorkPanel.addController(c);
        mainWindow.focusWorkPanel.update();
    }

    /***************************************************************************
     *                        Controllers | Resources
     ***************************************************************************/

    @Override
    public void visit(CreateResourceController c) {
        this.controllers.add(c);
        mainWindow.addResourcePanel(c);
    }

    /***************************************************************************
     *                        Controllers | Reservations
     ***************************************************************************/

    @Override
    public void visit(MakeResourceReservationController c) {
        this.controllers.add(c);
        mainWindow.addReservationPanel(c);
    }

    /***************************************************************************
     *                        Controllers | Focus Work
     ***************************************************************************/

    @Override
    public void visit(FocusWorkController c) {
        this.controllers.add(c);
        mainWindow.addFocusWorkPanel();
        mainWindow.focusWorkPanel.addController(c);
        mainWindow.focusWorkPanel.update();
    }
}